/* Copyright (c) 2004-2024 peigen.info. All rights reserved. */

package info.peigen.hotpot.common.service.base.time;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;
import lombok.experimental.SuperBuilder;

import java.time.*;
import java.util.Date;
import java.util.Objects;

/**
 * <b>(TimeRange)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2022/9/11
 */
@SuppressWarnings("unused")
@SuperBuilder
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Accessors(chain = true)
public class TimeRange implements TimeRangeParser {
    /** 起始时间 */
    @JSONField(ordinal = 1)
    LocalTime startTime;
    /** 截至时间 */
    @JSONField(ordinal = 2)
    LocalTime endTime;

    /**
     * 当前时间是否在时间指定范围内<br>
     * 起始时间和结束时间可以互换
     *
     * @param date      被检查的时间
     * @param startTime 起始时间（包含）
     * @param endTime   结束时间（不包含）
     *
     * @return 是否在范围内
     *
     * @since 3.0.8
     */
    public static Boolean isIn(Date date, LocalTime startTime, LocalTime endTime) {
        LocalDateTime startTimeLocalDateTime = startTime.atDate(LocalDate.now());
        Instant       startTimeInstant       = startTimeLocalDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date          startTimeDate          = Date.from(startTimeInstant);


        LocalDateTime endTimeLocalDateTime = endTime.atDate(LocalDate.now());
        if (endTime.equals(LocalTime.of(0, 0, 0))) {
            endTimeLocalDateTime = endTime.atDate(LocalDate.now()).plusDays(1L);
        }
        Instant endTimeInstant = endTimeLocalDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date    endTimeDate    = Date.from(endTimeInstant);

        if (startTimeDate.compareTo(endTimeDate) < 0) {
            long time = endTimeDate.getTime() - 1;
            endTimeDate = new Date(time);
        } else if (startTimeDate.compareTo(endTimeDate) > 0) {
            long time = endTimeDate.getTime() + 1;
            endTimeDate = new Date(time);
        }

        return DateUtil.isIn(date, startTimeDate, endTimeDate);
    }

    @Override
    public String parseStartTime() {
        return Objects.nonNull(startTime) ? startTime.toString() : null;
    }

    @Override
    public String parseEndTime() {
        return Objects.nonNull(endTime) ? endTime.toString() : null;
    }

    @Override
    public String between() {
        LocalDateTime startTimeLocalDateTime = startTime.atDate(LocalDate.now());
        Instant       startTimeInstant       = startTimeLocalDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date          startTimeDate          = Date.from(startTimeInstant);


        LocalDateTime endTimeLocalDateTime = endTime.atDate(LocalDate.now());
        Instant       endTimeInstant       = endTimeLocalDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date          endTimeDate          = Date.from(endTimeInstant);

        return DateUtil.secondToTime((int) DateUtil.between(startTimeDate, endTimeDate, DateUnit.SECOND));
    }

    public long between(DateUnit dateUnit) {
        LocalDateTime startTimeLocalDateTime = startTime.atDate(LocalDate.now());
        Instant       startTimeInstant       = startTimeLocalDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date          startTimeDate          = Date.from(startTimeInstant);


        LocalDateTime endTimeLocalDateTime = endTime.atDate(LocalDate.now());
        if (endTime.equals(LocalTime.of(0, 0, 0))) {
            endTimeLocalDateTime = endTime.atDate(LocalDate.now()).plusDays(1L);
        }
        Instant endTimeInstant = endTimeLocalDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date    endTimeDate    = Date.from(endTimeInstant);

        return DateUtil.between(startTimeDate, endTimeDate, dateUnit, false);
    }


}